package com.md.domain.service;

import com.google.common.collect.Lists;
import com.md.application.assembler.LogsAssembler;
import com.md.client.OpenApiClient;
import com.md.domain.model.bo.QueryLogsBO;
import com.md.domain.model.po.Logs;
import com.md.infrastructure.client.SystemClient;
import com.md.infrastructure.persistence.repository.LogsRepository;
import com.md.model.page.PageResponse;
import com.md.request.OperationLogsRequest;
import com.md.response.AppInfoResponse;
import com.md.response.LogsResponse;
import com.md.response.LogsTreeResponse;
import com.md.util.ClassUtils;
import com.md.util.CollectionUtil;
import com.md.util.ObjectUtil;
import com.md.util.PageUtil;
import com.md.value.constants.DefaultServerContext;
import com.md.value.server.ServerContext;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;

import static com.md.application.assembler.LogsAssembler.recursionChildrenOperateLogs;

/**
 * @author 刘骄阳
 * 2022-09-24 1:33
 */
@Service
@RequiredArgsConstructor
public class LogsDomainService {
  private final LogsRepository logsRepository;
  private final SystemClient systemClient;
//  private final AuthenticationClientService authenticationClientService;


  /**
   * 分页查询
   *
   * @return 查询结果
   */
  public PageResponse<Logs> selectRootLoByPage(final QueryLogsBO queryLogsBO) {
    return PageUtil.buildPageResponse(logsRepository.selectRootLoByPage(queryLogsBO));
  }

  /**
   * 递归查询子日志
   *
   * @param dataId 业务id
   * @return 树结构
   */
  public LogsTreeResponse recursionChildrenLogs(final String dataId) {
    Logs logs = new Logs();
    logs.setParentId(dataId);
    List<Logs> childrenLogs = logsRepository.selectList(logs);
    List<LogsTreeResponse> list = Lists.newArrayList();
    LogsTreeResponse response = new LogsTreeResponse();
    childrenLogs.forEach(childrenNode -> {
      LogsTreeResponse childResponse = LogsAssembler.poToTreeResponse(childrenNode, null);
      LogsTreeResponse childrenList = recursionChildrenLogs(childResponse.getDataId());
      if (ObjectUtils.isEmpty(childrenList)) {
        return;
      }
      childResponse.setChildren(childrenList.getChildren());
      list.add(childResponse);
    });
    response.setChildren(list);
    return response;
  }

  public LogsTreeResponse recursionParentLogs(final String dataId,
                                              final LogsTreeResponse returnResponse) {
    if (StringUtils.isBlank(dataId)) {
      return null;
    }
    Logs logs = new Logs();
    logs.setDataId(dataId);
    Logs parentLogs = logsRepository.select(logs);
    if (parentLogs == null) {
      return returnResponse;
    }
    LogsTreeResponse response = LogsAssembler.poToTreeResponse(parentLogs, null);
    response.setChildren(Collections.singletonList(returnResponse));
    LogsTreeResponse parentNode = recursionParentLogs(response.getParentId(), response);
    if (ObjectUtils.isEmpty(parentNode)) {
      return response;
    }
    return parentNode;
  }

  public LogsTreeResponse queryTreeOperateLogResponse(final Logs node) {
    List<Logs> logsList = queryByRootId(node.getRootId());
    Map<Long, AppInfoResponse> appInfoResponseMap =
      systemClient.getAppInfoResponseByIds(CollectionUtil.map(logsList, Logs::getAppInfoId));
    Map<String, List<Logs>> treeMap = CollectionUtil.groupBy(logsList, Logs::getParentId);
    LogsTreeResponse logsTreeResponse = recursionChildrenOperateLogs(treeMap, appInfoResponseMap, node);
    if (ObjectUtil.equals(node.getRootId(), node.getDataId())) {
      // 说明当前层级是根级
      return logsTreeResponse;
    } else {
      // 说明当前层级是中间层级
      return null;
    }

  }

  public Logs queryByDataId(final String dataId) {
    Logs logs = new Logs();
    logs.setDataId(dataId);
    return logsRepository.select(logs);
  }

  public List<Logs> queryByRootId(final String rootId) {
    Logs logs = new Logs();
    logs.setRootId(rootId);
    return logsRepository.selectList(logs);
  }

  public LogsResponse createLogs(final OperationLogsRequest request) {
    AppInfoResponse appInfoResponse = OpenApiClient.queryAppInfo(request.getTenantId(), request.getBrandId());
    Logs logs = ClassUtils.source2Target(request, Logs.class, t -> {
      t.setOperation(request.getOperation().getCode());
      t.setRootId(Optional.ofNullable(t.getParentId()).map(this::queryByDataId).map(Logs::getRootId)
        .orElse(t.getDataId()));
      t.setAppInfoId(appInfoResponse.getId());
    });
    ServerContext.put(DefaultServerContext.USER_ID, 0L);
    logsRepository.insert(logs);
    return LogsAssembler.poToResponse(logs, appInfoResponse);
  }

  public LogsResponse updateLogs(final OperationLogsRequest request) {
    ServerContext.put(DefaultServerContext.USER_ID, 0L);
    AppInfoResponse appInfoResponse = OpenApiClient.queryAppInfo(request.getTenantId(), request.getBrandId());
    Logs logs = ClassUtils.source2Target(request, Logs.class);
    if (ObjectUtil.isEmpty(logs.getId())) {
      Logs originalLog = logsRepository.selectByDataId(logs.getDataId());
      logs.setId(originalLog.getId());
    }
    logsRepository.update(logs);
    return LogsAssembler.poToResponse(logs, appInfoResponse);
  }
}
